/*
 * demo.cpp
 * This file is part of norxx
 *
 * Copyright (C) 2014 - Sebastian Gesemann
 *
 * norxx is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * norxx is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with norxx. If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include "array_ref.hpp"
#include "norx.hpp"

using util::array_ref;
using norx::u8;

std::ostream& operator<<(std::ostream& out, array_ref<const u8> data)
{
	static const char hex[] = "0123456789ABCDEF";
	while (!!data) {
		int octet = data.consume_first() & 0xFFu;
		out << hex[octet >> 4] << hex[octet & 0xF];
	}
	return out;
}

inline array_ref<const u8> cref(array_ref<const u8> tmp)
{
	return tmp;
}

int main()
{
	const int W=32;
	static const u8 key  [W/8*norx::key_words] = {1,2,3,4};
	static const u8 nonce[W/8*norx::nonce_words] = {5,6,7,8};
	static const u8 head [] = {1,1,1,1};
	static const u8 paylo[] = {'H','e','l','l','o'};
	static const u8 trail[] = {2,2,2,2};

	std::cout << "key    : " << cref(key  ) << std::endl;
	std::cout << "nonce  : " << cref(nonce) << std::endl;
	std::cout << "head   : " << cref(head ) << std::endl;
	std::cout << "payload: " << cref(paylo) << std::endl;
	std::cout << "trailer: " << cref(trail) << std::endl;

	norx::cipher<W> norxW;
	u8 ciphr[sizeof(paylo)];
	u8 atag [W/8*norx::atag_words_default];

	// encryption
	norxW.reset(key,nonce,4,1,sizeof(atag)); // setup
	norxW.feed(norx::domain_header,head);    // process given data as header
	{ // encrypting in two chunks (3+x bytes), multiple chunks are OK
	    array_ref<const u8> p = paylo;
	    array_ref<      u8> c = ciphr;
	    norxW.encrypt(p.consume_first_n(3),c.consume_first_n(3));
	    norxW.encrypt(p,c); // remainder
	}
	norxW.feed(norx::domain_trailer,trail);  // process given data as trailer
	norxW.tag_generate(atag);                // create authentication tag

	std::cout << "ciphert: " << cref(ciphr) << std::endl;
	std::cout << "atag   : " << cref(atag ) << std::endl;

	u8 decr[sizeof(paylo)];

	// decryption
	norxW.reset(key,nonce,4,1,sizeof(atag)); // setup
	norxW.feed(norx::domain_header,head);    // process given data as header
	norxW.decrypt(ciphr,decr);               // decrypt ciphr to decr
	norxW.feed(norx::domain_trailer,trail);  // process given data as trailer
	bool c = norxW.tag_check(atag);          // check authentication tag

	std::cout << "decrypt: " << cref(decr) << std::endl;
	std::cout << "atag   : " << (!c ? "in" : "") << "valid\n";
	return 0;
}

